package com.liqing.movecomment.filter;

import com.google.common.collect.Sets;
import com.liqing.movecomment.entity.User;
import com.liqing.movecomment.enums.Constent;
import com.liqing.movecomment.enums.RedisConstant;
import com.liqing.movecomment.exception.LdException;
import com.liqing.movecomment.exception.LdExceptionEnum;
import com.liqing.movecomment.util.JwtUtils;
import com.liqing.movecomment.util.RedisUtils;
import com.liqing.movecomment.util.ThreadLocalUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
 * Token过滤器
 */
@Component
public class TokenFilter extends OncePerRequestFilter {
    //<editor-fold defaultstate="collapsed" desc="delombok">
    @SuppressWarnings("all")
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TokenFilter.class);
    //</editor-fold>
    //路径匹配器，支持通配符
    // 需要放行的请求路径：验证码 登录 注册 注销
    private static final Set<String> ALLOW_PATH = Collections.unmodifiableSet(Sets.newHashSet("/favicon.ico", "/user/captcha", "/user/login", "/user/register", "/user/logout", "/file/upload", "/doc.html", "/swagger-resources", "/v2/api-docs", "/file/signalimage", "/file/uploadImage", "/file/**"));
    public static final String TOKEN = "token";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 获取请求的地址
        String uri = request.getRequestURI();
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        for (String path : ALLOW_PATH) {
            if (antPathMatcher.match(path, uri)) {
                // 放行请求
                filterChain.doFilter(request, response);
                return;
            }
        }
        if (uri.startsWith("/webjars/") || uri.startsWith("/file/")) {
            // 放行请求
            filterChain.doFilter(request, response);
        } else {
            // 从请求中获取token
            String token = getToken(request);
            // 如果token是空的，拦截请求返回没有权限
            //  final ServletOutputStream writer = response.getOutputStream();
            if (StringUtils.hasText(token)) {
                // 解析用户ID
                String uid = null;
                try {
                    uid = JwtUtils.parseToken(token);
                } catch (LdException e) {
                    log.error(e.getMessage());
                    returnJson(response, e);
                    e.printStackTrace();
                }
                // 从redis取出来用户放入ThreadLocal
                User user = (User) RedisUtils.getObject(RedisConstant.USER + uid);
                log.info("拦截了user==========》{}", user);
                if (ObjectUtils.isEmpty(user)) {
//
                    returnJson(response, new LdException(LdExceptionEnum.ERROR_TOKEN));
                } else {
                    ThreadLocalUtils.put(Constent.USER, user);
                    // 放行请求
                    filterChain.doFilter(request, response);
                }
            } else {
                filterChain.doFilter(request, response);
                // returnJson(response, new LdException(LdExceptionEnum.ERROR_TOKEN));
//
            }
        }
    }

    private void returnJson(HttpServletResponse response, LdException ldException) {
        PrintWriter writer = null;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setContentType("application/json;charset=UTF-8");
        try {
            writer = response.getWriter();
            Map<String, Object> map = new HashMap<>();
            map.put("code", ldException.getCode());
            map.put("msg", ldException.getDescription());
            writer.print(com.alibaba.fastjson.JSON.toJSONString(map));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * 从三个地方中获取token
     *
     * @param request 请求
     * @return {@link String}
     */
    private String getToken(HttpServletRequest request) {
        // token前端有可能是从header中传递也有可能是从cookie中传入也有可能从参数param中传传递
        String token = request.getHeader(TOKEN);
        if (!StringUtils.hasText(token)) {
            Cookie[] cookies = request.getCookies();
            if (Objects.nonNull(cookies) && cookies.length > 0) {
                for (Cookie cookie : cookies) {
                    if (Objects.equals(cookie.getName(), TOKEN)) {
                        token = cookie.getValue();
                    }
                }
                // for循环结束了 如果token还是空 说明cookie中也没有取到值，在从参数param中取值
                if (!StringUtils.hasText(token)) {
                    token = request.getParameter(TOKEN);
                }
            }
        }
        return token;
    }
}
